
Imports System.Text

Public Module stringUtils

    Public Function isemptystring(ByVal c() As Char) As Boolean
        Return c Is Nothing OrElse c.Length = 0
    End Function

    Public Function isemptystring(ByVal str As String) As Boolean
        Return str Is Nothing OrElse str.Length = 0
    End Function

    Public Function isemptystring(ByVal str As StringBuilder) As Boolean
        Return str Is Nothing OrElse str.Length = 0
    End Function

    Public Function nothingToEmptyString(ByVal s As String) As String
        Return ifoper(s Is Nothing, emptyString, s)
    End Function

    Public Function kickChars(ByRef str As String, ByVal kicks As String) As Boolean
        Dim rtn As Boolean = True

        If isemptystring(kicks) Then
            rtn = False
        Else
            Dim i As Int64
            i = 0
            While i < strlen(str)
                If kicks.IndexOf(str(i)) <> -1 Then
                    str = str.Remove(i, 1)
                    i -= 1
                End If
                i += 1
            End While

            rtn = True
        End If

        Return rtn
    End Function

    Public Function kickLeft(ByRef str As String, ByVal kickChars As String) As Boolean
        Dim i As Int64
        Dim len As Int64
        If isemptystring(str) Then
            Return False
        Else
            len = strlen(str)
            For i = 0 To len - 1
                If kickChars.IndexOf(str(i)) = -1 Then
                    Exit For
                End If
            Next
            If i > 0 Then
                str = strright(str, len - i)
            End If

            Return True
        End If
    End Function

    Public Function kickRight(ByRef str As String, ByVal kickChars As String) As Boolean
        Dim i As Int64
        Dim len As Int64
        If isemptystring(str) Then
            Return False
        Else
            len = strlen(str)
            For i = len - 1 To 0 Step -1
                If kickChars.IndexOf(str(i)) = -1 Then
                    Exit For
                End If
            Next
            If i < len - 1 Then
                str = strleft(str, i + 1)
            End If

            Return True
        End If
    End Function

    Public Function kickLeftRight(ByRef str As String, ByVal kickChars As String) As Boolean
        Return kickLeft(str, kickChars) AndAlso kickRight(str, kickChars)
    End Function

    Public Function kickLeftBlank(ByRef str As String) As Boolean
        Return kickLeft(str, spaceChars)
    End Function

    Public Function kickRightBlank(ByRef str As String) As Boolean
        Return kickRight(str, spaceChars)
    End Function

    Public Function kickLeftRightBlank(ByRef str As String) As Boolean
        Return kickLeftBlank(str) AndAlso kickRightBlank(str)
    End Function

    Public Sub cutstring(ByRef str As String, ByVal length As Int64)
        If Not str Is Nothing AndAlso str.Length > length Then
            str = str.Substring(0, length)
        Else
            str = emptyString
        End If
    End Sub

    Public Function ismark(ByVal c As Char) As Boolean
        Return marks.IndexOf(c) <> npos
    End Function

    Public Function isnewline(ByVal c As Char) As Boolean
        Return newlineChars.IndexOf(c) <> npos
    End Function

    Public Function isspace(ByVal c As Char) As Boolean
        Return Not isnotspace(c)
    End Function

    Public Function isnotspace(ByVal c As Char) As Boolean
        Return strindexof(spaceChars, c) = npos
    End Function

    Public Function isasciifit(ByVal c As Char) As Boolean
        Return c <= Chr(127) AndAlso c >= Chr(0)
    End Function

    Public Function isasciiextendfit(ByVal c As Char) As Boolean
        Return c <= Chr(255) AndAlso c >= Chr(0)
    End Function

    Public Function isleftbracket(ByVal c As Char) As Boolean
        Return defaultValue.leftBrackets.IndexOf(c) <> npos
    End Function

    Public Function isrightbracket(ByVal c As Char) As Boolean
        Return defaultValue.rightBrackets.IndexOf(c) <> npos
    End Function

    Public Function isbracket(ByVal c As Char) As Boolean
        Return isleftbracket(c) OrElse isrightbracket(c)
    End Function

    Public Function isdigit(ByVal c As Char) As Boolean
        If isdebugbuild() Then
            assert((defaultValue.digits.IndexOf(c) <> npos) = (isDBCDigit(c) OrElse isSBCDigit(c)))
        End If
        Return isDBCDigit(c) OrElse isSBCDigit(c)
    End Function

    Public Function isDBCDigit(ByVal c As Char) As Boolean
        Return defaultValue.dbcDigits.IndexOf (c) <> npos 
    End Function

    Public Function isSBCDigit(ByVal c As Char) As Boolean
        Return defaultValue.sbcDigits.IndexOf(c) <> npos
    End Function

    Public Function ishexdigit(ByVal c As Char) As Boolean
        Return defaultValue.hexdigits.IndexOf(c) <> npos
    End Function

    Public Function strform(ByVal str As String, ByVal f As charCheck) As Boolean
        Dim i As Int64 = 0
        Dim len As Int64 = 0
        If Not isemptystring(str) Then
            len = strlen(str)
            For i = 0 To len - 1
                If Not f(str(i)) Then
                    Exit For
                End If
            Next
        End If

        Return i = len
    End Function

    Public Sub kickNewlineChar(ByRef str As String)
        Dim i As Int64
        If Not isemptystring(str) Then
            i = str.Length() - 1
            While i >= 0 AndAlso (str(i) = character.newline OrElse _
                    str(i) = character.return)
                i -= 1
            End While
            str = strleft(str, i + 1)
        End If
    End Sub

#If UNDERDEBUGING Then
    Public Function kickBetween(ByRef content As String, ByRef left As String, ByRef right As String) As String
        Dim index As Int64 = 0
        Dim nextleft As Int64 = 0
        Dim nextright As Int64 = 0
        Dim len As Int64 = strlen(content)
        Dim bracket As Int64 = 0
        Dim leftlen As Int64 = strlen(left)
        Dim rightlen As Int64 = strlen(right)
        Dim rtn As String = Nothing
        While index < len
            nextleft = content.IndexOf(left, index)
            nextright = content.IndexOf(right, index)
            If (nextleft < nextright OrElse bracket = 0) AndAlso nextleft <> npos AndAlso nextright <> npos Then
                If bracket = 0 Then
                    rtn += strmid(content, index, nextleft - index)
                End If
                bracket += 1
                index = nextleft + leftlen
            ElseIf nextright <> npos AndAlso bracket > 0 Then
                bracket -= 1
                index = nextright + rightlen
            Else
                Exit While
            End If
        End While

        If index < len Andalso bracket = 0 Then
            rtn += strmid(content, index, len - index)
        End If

        content = rtn

        Return content
    End Function
#End If

    Public Function kickBetween(ByRef content As String, ByVal left As String, ByVal right As String) As String
        Dim i As Int64
        Dim bracket As Int64 = 0
        Dim rtn As Text.StringBuilder = Nothing
        Dim leftlen As Int64 = strlen(left)
        Dim rightlen As Int64 = strlen(right)
        rtn = New Text.StringBuilder(Convert.ToInt32(strlen(content)))
        For i = 0 To strlen(content) - 1
            If strsame(content, i, left, 0, leftlen) Then
                bracket += 1
                i += leftlen - 1
            ElseIf strsame(content, i, right, 0, rightlen) AndAlso bracket > 0 Then
                bracket -= 1
                i += rightlen - 1
            ElseIf bracket = 0 Then
                rtn.Append(content(i))
            End If
        Next

        content = rtn.ToString()

        Return content
    End Function

    Public Function hextochar(ByVal hex As String) As Char
        Return Convert.ToChar(Convert.ToInt32(hex, 16))
    End Function

    Public Function c_str(ByVal s As String) As Char()
        If s Is Nothing Then
            Return Nothing
        Else
            Return s.ToCharArray()
        End If
    End Function

    Public Function cstring(ByRef v As Byte()) As String
        Dim rtn As StringBuilder = Nothing
        rtn = New StringBuilder()
        Dim i As Int64 = 0
        While (v(i) <> 0)
            rtn.Append(Chr(v(i)))
            i += 1
        End While
        Return rtn.ToString()
    End Function

    Public Function string_byte(ByVal s As String) As Byte()
        If s Is Nothing Then
            Return Nothing
        Else
            Return encoding.utf8().GetBytes(s)
        End If
    End Function

    Public Function byte_string(ByVal bts() As Byte) As String
        If bts Is Nothing OrElse bts.Length = 0 Then
            Return Nothing
        Else
            Return encoding.utf8().GetString(bts)
        End If
    End Function

    Public Function charsame(ByVal c1 As Char, ByVal c2 As Char, Optional ByVal carecase As Boolean = True) As Boolean
        If carecase Then
            Return c1 = c2
        Else
            Return Char.ToLower(c1) = Char.ToLower(c2)
        End If
    End Function

    Public Function levenshtein(Of t As IComparable)(ByVal s1 As t(), ByVal s2 As t(), _
                                                        ByRef memstep(,) As Int64) As Int64
        assert(Not s1 Is Nothing AndAlso Not s2 Is Nothing, "s1 or s2 is nothing.")
        Dim i As Int64
        Dim j As Int64
        Dim len1 As Int64 = s1.Length
        Dim len2 As Int64 = s2.Length
        Dim rtn As Int64

        If len1 = 0 OrElse len2 = 0 Then
            rtn = len1
            If len2 > rtn Then
                rtn = len2
            End If
        Else
            ReDim memstep(len1, len2)

            For i = 0 To len1
                memstep(i, 0) = i
            Next

            For j = 0 To len2
                memstep(0, j) = j
            Next

            For i = 1 To len1
                For j = 1 To len2
                    If s1(i - 1).CompareTo(s2(j - 1)) = 0 Then
                        memstep(i, j) = min(memstep(i - 1, j - 1), min(memstep(i - 1, j), memstep(i, j - 1)) + 1)
                    Else
                        memstep(i, j) = min(memstep(i - 1, j - 1) + 1, min(memstep(i - 1, j), memstep(i, j - 1)) + 1)
                    End If
                Next
            Next

            rtn = memstep(len1, len2)
        End If

        Return rtn
    End Function

    Public Function levenshtein(Of t As IComparable)(ByVal s1 As t(), ByVal s2 As t()) As Int64
        Dim mem(,) As Int64 = Nothing
        Dim rtn As Int64 = levenshtein(s1, s2, mem)
        ReDim mem(-1, -1)

        Return rtn
    End Function

    Public Function editdist(ByVal s1 As String, ByVal s2 As String, Optional ByVal carecase As Boolean = True) As Int64
        If carecase Then
            Return levenshtein(s1.ToCharArray, s2.ToCharArray)
        Else
            Return levenshtein(s1.ToLower.ToCharArray, s2.ToLower.ToCharArray)
        End If
    End Function

    Public Function lendist(ByVal s1 As String, ByVal s2 As String) As Int64
        Return Math.Abs(strlen(s1) - strlen(s2))
    End Function

    Public Function strchrcount(ByVal s As String, ByVal c As Char) As Int64
        Dim i As Int64
        Dim count As Int64
        count = -1
        i = -1
        Do
            count += 1
            i = s.IndexOf(c, Convert.ToInt32(i + 1))
        Loop Until i = npos

        Return count
    End Function

    Public Function charsCount(ByVal s As String, ByVal f As String) As Int64
        Dim count As Int64
        Dim i As Int64

        count = 0
        For i = 0 To strlen(s) - 1
            If f.IndexOf(s(i)) <> -1 Then
                count += 1
            End If
        Next

        Return count
    End Function

    Public Function revert(ByRef str As String) As String
        Dim rtn As String = Nothing
        Dim i As Int64
        For i = 0 To strlen(str) - 1
            rtn = str(i) + rtn
        Next

        Return rtn
    End Function

    Public Function strcombine(ByVal s() As String, ByVal seperator As String) As String
        Dim rtn As StringBuilder = Nothing
        rtn = New StringBuilder()
        If Not s Is Nothing AndAlso s.Length > 0 Then
            Dim i As Int64
            For i = 0 To s.Length() - 2
                rtn.Append(s(i))
                rtn.Append(seperator)
            Next
            rtn.Append(s(i))
        End If

        Return Convert.ToString(rtn)
    End Function

    Public Function strleft(ByVal str As String, ByVal length As Int64) As String
        If length > 0 Then
            If strlen(str) > length Then
                Return str.Substring(0, length)
            Else
                Return str
            End If
        Else
            Return Nothing
        End If
    End Function

    Public Function strright(ByVal str As String, ByVal length As Int64) As String
        Dim len As Int64 = strlen(str)
        If length <= 0 Then
            Return Nothing
        ElseIf length >= len Then
            Return str
        Else
            Return str.Substring(len - length)
        End If
    End Function

    Public Function strmid(ByVal str As String, ByVal start As Int64, Optional ByVal len As Int64 = -1) As String
        Dim rtn As String = Nothing
        Dim strl As Int64 = strlen(str)
        If start < 0 Then
            start = 0
        End If
        If len = -1 Then
            len = strl
        End If
        If start >= strl OrElse len <= 0 Then
            rtn = emptyString
        ElseIf start + len <= strl Then
            rtn = str.Substring(start, len)
        ElseIf start + len > strl Then
            rtn = strright(str, strl - start)
        End If

        Return rtn
    End Function

    Public Function strlen(ByVal input As String) As Int64
        If isemptystring(input) Then
            Return 0
        Else
            Return input.Length()
        End If
    End Function

    Public Function strlen(ByVal input As StringBuilder) As Int64
        If isemptystring(input) Then
            Return 0
        Else
            Return input.Length()
        End If
    End Function

    Public Function strcmp(ByVal input1 As String, ByVal start1 As Int64, ByVal len1 As Int64, _
                            ByVal input2 As String, ByVal start2 As Int64, ByVal len2 As Int64, _
                            Optional ByVal careCase As Boolean = True) As Int64
        If careCase Then
            Return String.Compare(strmid(input1, start1, len1), _
                                    strmid(input2, start2, len2))
        Else
            Return String.Compare(strmid(input1, start1, len1).ToLower, _
                                    strmid(input2, start2, len2).ToLower)
        End If
    End Function

    Public Function strcmp(ByVal input1 As String, ByVal start1 As Int64, _
                            ByVal input2 As String, ByVal start2 As Int64, ByVal len As Int64, _
                            Optional ByVal carecase As Boolean = True) As Int64
        Return strcmp(input1, start1, len, input2, start2, len, carecase)
    End Function

    Public Function strcmp(ByVal s1 As String, ByVal s2 As String, ByVal len As Int64, _
                            Optional ByVal carecase As Boolean = True) As Int64
        Return strcmp(s1, 0, len, s2, 0, len, carecase)
    End Function

    Public Function strcmp(ByVal s1 As String, ByVal s2 As String, _
                            Optional ByVal carecase As Boolean = True) As Int64
        Return strcmp(s1, 0, strlen(s1), s2, 0, strlen(s2), carecase)
    End Function

    Public Function strcmp(ByVal s1 As StringBuilder, ByVal start1 As Int64, ByVal len1 As Int64 _
                           , ByVal s2 As StringBuilder, ByVal start2 As Int64, ByVal len2 As Int64 _
                           , Optional ByVal carecase As Boolean = True) As Int64
        On Error Resume Next
        Dim ss1 As String = Nothing
        ss1 = s1.ToString(start1, min(len1, strlen(s1) - start1))
        Dim ss2 As String = Nothing
        ss2 = s2.ToString(start2, min(len2, strlen(s2) - start2))
        Return strcmp(ss1, 0, len1, ss2, 0, len2, carecase)

#If RETIRED Then
        Dim emps1 As Boolean = isemptystring(s1)
        Dim emps2 As Boolean = isemptystring(s2)
        If emps1 AndAlso emps2 Then
            Return 0
        ElseIf emps1 Then
            Return -1
        ElseIf emps2 Then
            Return 1
        End If
        Dim overs1 As Boolean = start1 + len1 >= s1.Length OrElse start1 < 0 OrElse len1 < 0
        Dim overs2 As Boolean = start2 + len2 >= s2.Length OrElse start2 < 0 OrElse len2 < 0
        If overs1 AndAlso overs2 Then
            Return 0
        ElseIf overs1 Then
            Return -1
        ElseIf overs2 Then
            Return 1
        End If

        Return strcmp(s1.ToString(start1, len1), 0, len1, s2.ToString(start2, len2), 0, len2, carecase)

        Dim i As Int64
        Dim j As Int64
        i = start1
        j = start2
        While i < start1 + len1 AndAlso j < start2 + len2 _
            AndAlso ifoper(carecase, s1(i) = s2(j), Char.ToLower(s1(i)) = Char.ToLower(s2(j)))
            i += 1
            j += 1
        End While

        If i < start1 + len1 AndAlso j < start2 + len2 Then
            Return (ifoper(carecase, Convert.ToInt32(s1(i)) - Convert.ToInt32(s2(j)) _
                           , Convert.ToInt32(Char.ToLower(s1(i))) - Convert.ToInt32(Char.ToLower(s2(j)))))
        ElseIf i < start1 + len1 Then
            Return 1
        ElseIf j < start2 + len2 Then
            Return -1
        Else
            Return 0
        End If
#End If
    End Function

    Public Function strcmp(ByVal s1 As StringBuilder, ByVal start1 As Int64, ByVal len1 As Int64 _
                           , ByVal s2 As String, ByVal start2 As Int64, ByVal len2 As Int64 _
                           , Optional ByVal carecase As Boolean = True) As Int64
        On Error Resume Next
        Dim ss1 As String = Nothing
        ss1 = s1.ToString(start1, min(len1, strlen(s1) - start1))
        Return strcmp(ss1, 0, len1, s2, start2, len2, carecase)

#If RETIRED Then
        Dim emps1 As Boolean = isemptystring(s1)
        Dim emps2 As Boolean = isemptystring(s2)
        If emps1 AndAlso emps2 Then
            Return 0
        ElseIf emps1 Then
            Return -1
        ElseIf emps2 Then
            Return 1
        End If
        Dim overs1 As Boolean = start1 + len1 >= s1.Length OrElse start1 < 0 OrElse len1 < 0
        Dim overs2 As Boolean = start2 + len2 >= s2.Length OrElse start2 < 0 OrElse len2 < 0
        If overs1 AndAlso overs2 Then
            Return 0
        ElseIf overs1 Then
            Return -1
        ElseIf overs2 Then
            Return 1
        End If

        Return strcmp(s1.ToString(start1, len1), 0, len1, s2, start2, len2, carecase)
#End If
    End Function

    Public Function strcmp(ByVal s1 As String, ByVal start1 As Int64, ByVal len1 As Int64 _
                           , ByVal s2 As StringBuilder, ByVal start2 As Int64, ByVal len2 As Int64 _
                           , Optional ByVal carecase As Boolean = True) As Int64
        Return -strcmp(s2, start2, len2, s1, start1, len1, carecase)
    End Function

    Public Function strsame(ByVal input1 As String, ByVal start1 As Int64, _
                            ByVal input2 As String, ByVal start2 As Int64, ByVal len As Int64, _
                            Optional ByVal careCase As Boolean = True) As Boolean
        If len = 0 Then
            Return True
        ElseIf isemptystring(input1) AndAlso isemptystring(input2) Then
            Return True
        ElseIf isemptystring(input1) OrElse isemptystring(input2) Then
            Return False
        ElseIf start1 >= input1.Length OrElse start2 >= input2.Length Then
            Return False
        Else
            Return strcmp(input1, start1, len, input2, start2, len, careCase) = 0
        End If
    End Function

    Public Function strsame(ByVal input1 As String, ByVal start1 As Int64, ByVal len1 As Int64, _
                            ByVal input2 As String, ByVal start2 As Int64, ByVal len2 As Int64, _
                            Optional ByVal careCase As Boolean = True) As Boolean
        If len1 <> len2 Then
            Return False
        Else
            Return strsame(input1, start1, input2, start2, len1, careCase)
        End If
    End Function

    Public Function strsame(ByVal input1 As String, ByVal input2 As String, ByVal len As Int64, _
                            Optional ByVal careCase As Boolean = True) As Boolean
        Return strsame(input1, 0, input2, 0, len, careCase)
    End Function

    Public Function strsame(ByVal input1 As String, ByVal len1 As Int64, _
                            ByVal input2 As String, ByVal len2 As Int64, _
                            Optional ByVal careCase As Boolean = True) As Boolean
        Return strsame(input1, 0, len1, input2, 0, len2, careCase)
    End Function

    Public Function strsame(ByVal input1 As String, ByVal input2 As String, _
                            Optional ByVal careCase As Boolean = True) As Boolean
        Return strsame(input1, 0, strlen(input1), input2, 0, strlen(input2), careCase)
    End Function

    Public Function strendwith(ByVal s1 As String, ByVal s2 As String, _
                               Optional ByVal careCase As Boolean = True) As Boolean
        Return strsame(s1, strlen(s1) - strlen(s2), s2, 0, strlen(s2), careCase)
    End Function

    Public Function strstartwith(ByVal s1 As String, ByVal s2 As String, _
                                 Optional ByVal careCase As Boolean = True) As Boolean
        Return strsame(s1, 0, s2, 0, strlen(s2), careCase)
    End Function

    Public Function strcont(ByVal str As String, ByVal f As charcheck) As Boolean
        Dim i As Int64 = 0
        Dim len As Int64 = 0
        If Not isemptystring(str) Then
            len = strlen(str)
            For i = 0 To len - 1
                If f(str(i)) Then
                    Exit For
                End If
            Next
        End If

        Return i < len
    End Function

    Private Delegate Function indexDelegate(ByVal s As String, ByVal search As String, ByRef start As Int64) As Int64

    Private Function strindexofImpl(ByVal s As String, ByVal search As String, ByRef start As Int64) As Int64
        Dim rtn As Int64
        rtn = s.IndexOf(search, Convert.ToInt32(start))
        start = rtn + strlen(search)

        Return rtn
    End Function

    Private Function strlastindexofImpl(ByVal s As String, ByVal search As String, ByRef start As Int64) As Int64
        Dim rtn As Int64
        rtn = s.LastIndexOf(search, Convert.ToInt32(start))
        start = rtn - strlen(search)

        Return rtn
    End Function

    Private Function strindexofImpl(ByVal s As String, ByVal search As String, ByVal start As Int64, _
                                    ByVal indexOfIndex As Int64, ByVal indexcall As indexDelegate, _
                                    ByVal carecase As Boolean) As Int64
        If isemptystring(search) Then
            Return 0
        ElseIf isemptystring(s) Then
            Return npos
        ElseIf indexOfIndex <= 0 Then
            Return 0
        Else
            If Not carecase Then
                s = s.ToLower()
                search = search.ToLower()
            End If
            Dim searchlen As Int32
            searchlen = strlen(search)
            Dim rtn As Int32
            Dim nextSearch As Int64
            nextSearch = start
            Dim i As Int64
            For i = 0 To indexOfIndex - 1
                rtn = indexcall(s, search, nextSearch)
                If rtn = npos Then
                    Exit For
                ElseIf (nextSearch < 0 OrElse nextSearch >= strlen(s)) AndAlso i < indexOfIndex - 1 Then
                    'cannot search for one more time, so the rtn should be npos
                    rtn = npos
                    Exit For
                End If
            Next

            Return rtn
        End If
    End Function

    Public Function strindexof(ByVal s As String, ByVal search As String, _
                               Optional ByVal carecase As Boolean = True) As Int64
        Return strindexof(s, search, 1, carecase)
    End Function

    Public Function strindexof(ByVal s As String, ByVal search As String, ByVal indexOfIndex As Int64, _
                               Optional ByVal carecase As Boolean = True) As Int64
        Return strindexof(s, search, 0, indexOfIndex, carecase)
    End Function

    Public Function strindexof(ByVal s As String, ByVal search As String, ByVal start As Int64, _
                               ByVal indexOfIndex As Int64, Optional ByVal carecase As Boolean = True) As Int64
        Return strindexofImpl(s, search, start, indexOfIndex, AddressOf strindexofImpl, carecase)
    End Function

    Public Function strlastindexof(ByVal s As String, ByVal search As String, _
                                   Optional ByVal carecase As Boolean = True) As Int64
        Return strlastindexof(s, search, 1, carecase)
    End Function

    Public Function strlastindexof(ByVal s As String, ByVal search As String, ByVal indexOfIndex As Int64, _
                                   Optional ByVal carecase As Boolean = True) As Int64
        Return strlastindexof(s, search, strlen(s) - 1, indexOfIndex, carecase)
    End Function

    Public Function strlastindexof(ByVal s As String, ByVal search As String, ByVal start As Int64, _
                                   ByVal indexOfIndex As Int64, Optional ByVal carecase As Boolean = True) As Int64
        Return strindexofImpl(s, search, start, indexOfIndex, AddressOf strlastindexofImpl, carecase)
    End Function

    Public Function strcont(ByVal s As String, ByVal contain As String _
                            , Optional ByVal carecase As Boolean = True) As Boolean
        Return strindexof(s, contain, carecase) <> npos
    End Function

    Public Function strrplc(ByRef str As String, ByVal index As Int64, ByVal s As String) As String
        If Not isemptystring(str) Then
            Select Case strlen(str)
                Case Is > index
                    str = strleft(str, index) + s + strmid(str, index + strlen(s))
                Case index
                    str += s
            End Select
        End If
        Return str
    End Function

    Public Function strrplc(ByRef s As String, ByVal [from] As String, ByVal [to] As String) As String
        If Not isemptystring(s) AndAlso Not isemptystring([from]) Then
            s = s.Replace([from], [to])
#If RETIRED Then
            Dim i As Int32
            Dim tolen As Int32 = strlen([to])
            Dim fromlen As Int32 = strlen([from])
            i = 0
            i = s.IndexOf([from])
            While i <> npos
                s = strleft(s, i) + [to] + strmid(s, i + fromlen)
                i += tolen
                i = s.IndexOf(from, i)
            End While

            Return True
#End If
        End If

        Return s
    End Function

    Public Function strrept(ByVal str As String, ByVal repeat As Int64) As String
        Dim rtn As String = emptyString
        While repeat > 0
            rtn += str
            repeat -= 1
        End While

        Return rtn
    End Function

    Public Function strrmv(ByRef s As String, ByVal start As Int64, Optional ByVal len As Int64 = npos) As Boolean
        If strlen(s) <= start Then
            Return False
        Else
            If len = npos OrElse strlen(s) < start + len Then
#If Not (PocketPC OrElse Smartphone) Then
                s = s.Remove(start)
#Else
                s = s.Remove(start, strlen(s) - start)
#End If
            Else
                s = s.Remove(start, len)
            End If
            Return True
        End If
    End Function

    Public Function strcat(ByVal ParamArray p() As Object) As String
        Dim s As StringBuilder = Nothing
        If Not p Is Nothing AndAlso p.Length() > 0 Then
            s = New StringBuilder()
            For i As Int32 = 0 To p.Length() - 1
                s.Append(Convert.ToString(p(i)))
            Next
        End If
        Return Convert.ToString(s)
    End Function

    Public Delegate Function strcatDelegate(ByRef dest As String, ByVal src As String) As String

    Public Function strncatImpl(ByRef dest As String, ByVal src As String, ByVal count As Int64 _
                                , ByRef impl As strcatDelegate) As String
        Dim len As Int64 = strlen(src)
        If len > 1 Then
            While count > 0
                impl(dest, src)
                count -= 1
            End While
        Else
            impl(dest, New String(src(0), count))
        End If
        Return dest
    End Function

    Public Function strcat(ByRef dest As String, ByVal src As String) As String
        dest += src
        Return dest
    End Function

    Public Function strrcat(ByRef dest As String, ByVal src As String) As String
        dest = src + dest
        Return dest
    End Function

    Public Function strncat(ByRef dest As String, ByVal src As String, ByVal count As Int64) As String
        Return strncatImpl(dest, src, count, AddressOf strcat)
    End Function

    Public Function strrncat(ByRef dest As String, ByVal src As String, ByVal count As Int64) As String
        Return strncatImpl(dest, src, count, AddressOf strrcat)
    End Function

    Public Delegate Function strncatDelegate(ByRef dest As String, ByVal src As String, ByVal count As Int64) As String

    Public Function strfillImpl(ByRef dest As String, ByVal src As String, ByVal length As Int64, _
                                ByRef impl As strncatDelegate) As String
        Dim requiredTimes As Int64 = length - strlen(dest)
        If requiredTimes <> 0 Then
            Dim srclen As Int64 = strlen(src)
            assert(srclen > 0, "src is nothing or emptystring, cannot fill to required length.")
            assert(requiredTimes >= 0, "dest length is already over length.")
            assert(requiredTimes / srclen = requiredTimes \ srclen, "requiredTimes is not an integer.")
            requiredTimes /= srclen
            impl(dest, src, requiredTimes)
        End If
        Return dest
    End Function

    Public Function strfill(ByRef dest As String, ByVal src As String, ByVal length As Int64) As String
        Return strfillImpl(dest, src, length, AddressOf strncat)
    End Function

    Public Function strrfill(ByRef dest As String, ByVal src As String, ByVal length As Int64) As String
        Return strfillImpl(dest, src, length, AddressOf strrncat)
    End Function

    Public Const maxcharWidth As Byte = 3

    Public Function charwidth(ByRef c As Char) As Byte
        If language.english.isalpha(c) Then
            Return 1
        ElseIf language.english.sbc.isalpha(c) Then
            Return 2
        ElseIf language.CJKShare.isCJKHanzi(c) Then
            Return 2
        ElseIf ismark(c) Then
            If isasciiextendfit(c) Then
                Return 1
            Else
                Return 2
            End If
        ElseIf isnewline(c) Then
            Return 0
        ElseIf isspace(c) Then
            If isasciiextendfit(c) Then
                Return 1
            Else
                Return 2
            End If
        ElseIf isdigit(c) Then
            If isasciiextendfit(c) Then
                Return 1
            Else
                Return 2
            End If
        Else
            Return maxcharWidth
        End If
    End Function

    Public Function stringwidth(ByVal s As String) As Int64
        Return stringwidth(s, 0, strlen(s))
    End Function

    Public Function stringwidth(ByVal s As String, ByVal start As Int64, ByVal [end] As Int64) As Int64
        Dim i As Int64
        i = start
        If i < 0 Then
            i = 0
        End If
        Dim till As Int64
        till = strlen(s)
        If [end] < till Then
            till = [end]
        End If
        Dim rtn As Int64
        rtn = 0
        While i < till
            rtn += charwidth(s(i))
            i += 1
        End While

        Return rtn
    End Function

    Public Function lastlines(ByVal s As String, ByVal linecount As Int64, ByVal linewidth As Int64) As String
        Dim index As Int32
        Dim thisindex As Int32
        index = strlen(s)
        While linecount > 0 AndAlso index > 0
            thisindex = s.LastIndexOf(character.newline, index - 1)
            If thisindex = npos Then
                thisindex = -1
            End If
            Dim thislinecount As Int64
            thislinecount = stringwidth(s, thisindex + 1, index)
            If thislinecount = 0 Then
                thislinecount = 1
            Else
                thislinecount = (thislinecount + linewidth - 1) \ linewidth
            End If
            If linecount < thislinecount Then
                Exit While
            Else
                linecount -= thislinecount
                index = thisindex
            End If
        End While

        Return strmid(s, index)
    End Function

    Private Delegate Function strindexofDelegate(ByVal s As String, ByVal search As String, _
                                                 ByVal carecase As Boolean) As Int64

    Private Function _strseg(ByVal input As String, _
                             ByRef f As String, ByRef s As String, _
                             ByVal separator As String, _
                             ByVal indexof As strindexofDelegate, _
                             Optional ByVal carecase As Boolean = True) As Boolean
        Dim index As Int64
        index = indexof(input, separator, carecase)
        If index = npos Then
            Return False
        Else
            f = strleft(input, index)
            s = strmid(input, index + strlen(separator))
            Return True
        End If
    End Function

    Public Function strseg(ByVal input As String, _
                           ByRef f As String, ByRef s As String, _
                           ByVal separator As String, _
                           Optional ByVal carecase As Boolean = True) As Boolean
        Return _strseg(input, f, s, separator, AddressOf strindexof, carecase)
    End Function

    Public Function strrseg(ByVal input As String, _
                            ByRef f As String, ByRef s As String, _
                            ByVal separator As String, _
                            Optional ByVal carecase As Boolean = True) As Boolean
        Return _strseg(input, f, s, separator, AddressOf strlastindexof, carecase)
    End Function

    Public Function strtolower(ByRef s As String) As String
        If Not s Is Nothing Then
            s = s.ToLower()
        End If

        Return s
    End Function

    Public Function strtoupper(ByRef s As String) As String
        If Not s Is Nothing Then
            s = s.ToUpper()
        End If

        Return s
    End Function

    Public Function strtolower(Of T)(ByVal i As T) As String
        Return strtolower(Convert.ToString(i))
    End Function

    Public Function strtoupper(Of T)(ByVal i As T) As String
        Return strtoupper(Convert.ToString(i))
    End Function

    Public Sub free(ByRef sb As StringBuilder)
        If Not sb Is Nothing Then
            sb.Length = 0
            sb.Capacity = 0
            sb = Nothing
        End If
    End Sub

    Public Function truncate(ByVal s As String, ByVal maxwidth As Int64) As String
        Dim len As Int64
        len = strlen(s)
        If len > (maxwidth / maxcharWidth) Then
            Static ellipsisString As String = Global.character.blank + ellipsis
            Dim i As Int64
            Dim width As Int64 = 0
            maxwidth -= stringwidth(ellipsisString)
            For i = 0 To len - 1
                width += charwidth(s(i))
                If width > maxwidth Then
                    Exit For
                End If
            Next
            If i < len Then
                Return strleft(s, i) + ellipsisString
            Else
                Return s
            End If
        Else
            Return s
        End If
    End Function

    Public Structure lazyStrCat
        Private ps() As Object

        Public Sub New(ByVal p As Object, ByVal ParamArray ps() As Object)
            If Not ps Is Nothing AndAlso ps.Length() > 0 Then
                ReDim Me.ps(ps.Length())
                memcpy(Me.ps, 1, ps, 0, ps.Length())
            Else
                ReDim Me.ps(0)
            End If
            Me.ps(0) = p
        End Sub

        Public Sub New(ByVal ps() As Object)
            Me.ps = ps
        End Sub

        Public Overrides Function ToString() As String
            Return strcat(ps)
        End Function
    End Structure
End Module
